#pragma once

#include <memory>
#include "Containers/String.h"
#include "Containers/Any.h"

class CExpressionNode;
class CType;

//constant value type in script compile time
enum class EConstantValueType : uint8_t //clarify the size of the enum for serialization 
{
    Unknown,
    String,
    Char,
    Bool,
    Int8,
    Int16,
    Int32,
    Int64,
    UInt8,
    UInt16,
    UInt32,
    UInt64,
    Float,
    Double,
};

class CConstantValue
{
public:
    CConstantValue()
        : Type(EConstantValueType::Unknown)
    {
    }

    CConstantValue(const CString& InStringValue)
        : Type(EConstantValueType::String)
        , StringValue(InStringValue)
    {
    }

    CConstantValue(char32_t InChar)
        : Type(EConstantValueType::Char)
        , CharValue(InChar)
    {
    }

    CConstantValue(bool InBoolValue)
        : Type(EConstantValueType::Bool)
        , BoolValue(InBoolValue)
    {
    }

    CConstantValue(int8_t InInt8Value)
        : Type(EConstantValueType::Int8)
        , Int8Value(InInt8Value)
    {
    }

    CConstantValue(int16_t InInt16Value)
        : Type(EConstantValueType::Int16)
        , Int16Value(InInt16Value)
    {
    }

    CConstantValue(int32_t InInt32Value)
        : Type(EConstantValueType::Int32)
        , Int32Value(InInt32Value)
    {
    }

    CConstantValue(int64_t InInt64Value)
        : Type(EConstantValueType::Int64)
        , Int64Value(InInt64Value)
    {
    }

    CConstantValue(uint8_t InUInt8Value)
        : Type(EConstantValueType::UInt8)
        , UInt8Value(InUInt8Value)
    {
    }

    CConstantValue(uint16_t InUInt16Value)
        : Type(EConstantValueType::UInt16)
        , UInt16Value(InUInt16Value)
    {
    }

    CConstantValue(uint32_t InUInt32Value)
        : Type(EConstantValueType::UInt32)
        , UInt32Value(InUInt32Value)
    {
    }

    CConstantValue(uint64_t InUInt64Value)
        : Type(EConstantValueType::UInt64)
        , UInt64Value(InUInt64Value)
    {
    }

    CConstantValue(float InFloatValue)
        : Type(EConstantValueType::Float)
        , FloatValue(InFloatValue)
    {
    }

    CConstantValue(double InDoubleValue)
        : Type(EConstantValueType::Double)
        , DoubleValue(InDoubleValue)
    {
    }

    EConstantValueType Type;

    CType* GetType() const;

    CAny ToAny() const;

    union
    {
        char32_t CharValue;
        bool BoolValue;
        int8_t Int8Value;
        int16_t Int16Value;
        int32_t Int32Value;
        int64_t Int64Value;
        uint8_t UInt8Value;
        uint16_t UInt16Value;
        uint32_t UInt32Value;
        uint64_t UInt64Value;
        float FloatValue;
        double DoubleValue;
    };
    CString StringValue;
};
